/*
 * @Author: 9ilk 3535851673@qq.com
 * @Date: 2025-01-16 18:39:38
 * @LastEditors: 9ilk 3535851673@qq.com
 * @LastEditTime: 2025-01-16 18:59:53
 * @FilePath: /zhuang/TCP/EchoServer/ThreadPool.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#pragma once
#include <iostream>
#include <string>
#include <queue>
#include <vector> //用来管理线程
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"
#include "Log.hpp"
using namespace std;

namespace ThreadPoolModule
{
   using namespace LockModule;
   using namespace CondModule;
   using namespace LogModule;
   using namespace ThreadModule;

   // 用来做线程测试的方法
   void DefaultTest()
   {
      while (true)
      {
         LOG(LogLevel::DEBUG) << "我是测试代码" << "\n";
         sleep(1);
      }
   }
   const static int defaultnum = 10;          // 默认线程池内线程数目
   using thread_t = std::shared_ptr<Thread>; // 线程对象让智能指针托管减少拷贝

   template <typename T>
   class ThreadPool
   {
   private:
      bool isEmpty() { return _taskq.empty(); }
      
      void HandlerTask(string name) //
      {
         LOG(LogLevel::INFO) << "线程: "<< name <<"进入HandlerTask...\n";
         while (true) // 所有启动的线程应该不断重复这两步骤
         {            // 1.拿任务
            T t;
            {
               LockGuard lockguard(_lock); // 拿任务加锁
               while (isEmpty() && _isrunning)   // 没有任务 任务队列为空&&运行才等待
               {
                  _wait_num++;
                  _cond.Wait(_lock);
                  _wait_num--;
               }
               //走到这: 任务队列为空  线程池退出;当两条件都达到才break
               if(isEmpty() &&  !_isrunning) break;
               t = _taskq.front(); // 拿出任务
               _taskq.pop();       // 移除任务队列
            }
            // 2.处理任务
            t(); // 规定,未来所有的任务处理,全部都是必须提供()方法
         }
         LOG(LogLevel::INFO) << "线程: "<< name <<"退出...\n";
      }
      ThreadPool(const ThreadPool<T> & tp) = delete; 
      const ThreadPool<T>& operator=(const ThreadPool<T> & tp) = delete; 
      //构造要但是设置私有
          ThreadPool(int num = defaultnum)
          : _num(num),_wait_num(0),_isrunning(false)
      {
         // 线程池启动前先把线程创建出来
         for (int i = 0; i < _num; i++)
         {
            _threads.push_back(make_shared<Thread>(std::bind(&ThreadPool::HandlerTask,this,std::placeholders::_1)));
            LOG(LogLevel::INFO) << "构建线程" << _threads.back()->Name() << "成功\n";
         }
      }

   public:
   //获取单例的方法
      static ThreadPool<T>* getInstance()
      {
         if(instance == NULL)
         {
           LockGuard lockguard(_mutex);
           if(instance == NULL)
           {
             LOG(LogLevel::INFO) << "单例实例正在创建...\n"; 
             instance = new ThreadPool<T>();
             instance->Start();
           }
         }
         return instance; 
      }
  
      ~ThreadPool() {}

      void Enqueue( T in)
      {
         if(!_isrunning) return; //没有在运行就不入队列
         LockGuard lockguard(_lock);
         // _taskq.push(std::move(in));
         _taskq.push(in);
         if(_wait_num > 0) _cond.Notify(); //唤醒
      }

      void Wait() // 曾经运行的线程都停止
      {
         for (auto &thread_ptr : _threads)
         {
            thread_ptr->Join();
            LOG(LogLevel::INFO) << "回收线程" << thread_ptr->Name() << "成功\n";
         }
      }

      void Start()
      {
         if(_isrunning) return; //已经启动
         _isrunning = true; //start完标记
         for (auto &thread_ptr : _threads)
         {
            thread_ptr->Start();
            LOG(LogLevel::INFO) << "启动线程" << thread_ptr->Name() << "成功\n";
         }
      }
      void Stop()
      {
         LockGuard lockguard(_lock);
         if(_isrunning) //前提是运行
         { 
            _isrunning = false;//不工作状态->不能再入任务
            if(_wait_num > 0) //当前在线程池中有休眠的，让线程自己退出(要唤醒)
              _cond.NotifyAll(); //让他们把本轮的任务都处理完处理完历史任务
         }
      }
      
   private:
      int _num;
      vector<thread_t> _threads; // 管理线程对象
      queue<T> _taskq;           // 任务队列 临界资源
      Mutex _lock;
      Cond _cond;
      int _wait_num;
      bool _isrunning;
      static Mutex _mutex; //只用来保护单例
      static ThreadPool<T>* instance;
   };

   //静态成员初始化需要放类外
   template<typename T>
   ThreadPool<T>* ThreadPool<T>::instance = NULL;
   template<typename T>
   Mutex ThreadPool<T>::_mutex;
}
